/**
 * huize Service Inc
 * All Rights Reserved @2018
 */
package com.huize.ladon.apm.common.util;

import com.huize.ladon.apm.common.enums.IpZoneTypeEnum;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.util.regex.Matcher;
import java.util.regex.Pattern;


/**
 * 描述: IP地址校验
 *
 * @author tianyuliang
 * @version $Id: IpUtils.java, v0.1 2020/7/20
 */
@Slf4j
public class IpUtils {

    public static final String IP_SPILT_SYMBOL = "\\.";

    public static final String RULE_IP_PATTERN = "([1-9]|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])(\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])){3}";

    public static final String RULE_IPV6_PATTERN = "((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:)))(%.+)?";

    public static final Pattern IP_PATTERN = Pattern.compile(RULE_IP_PATTERN);

    public static final Pattern IPV6_PATTERN = Pattern.compile(RULE_IPV6_PATTERN);

    /**
     * 校验是否为公网IP
     *
     * @param ipAddress
     * @return 返回true:是公网IP, 返回false:不是公网IP
     */
    public static boolean checkPublicIp(String ipAddress) {
        if (StringUtils.isBlank(ipAddress)) {
            return false;
        }
        boolean hasIpV4 = checkIp(ipAddress.trim());
        if (!hasIpV4) {
            return false;
        }

        IpZoneTypeEnum zoneTypeEnum = convertIpZoneType(ipAddress.trim());
        boolean publicIp = IpZoneTypeEnum.isPublicIp(zoneTypeEnum);
        return publicIp;
    }

    /**
     * 判断是否为精确的、有效IP
     *
     * @param ipAddress 待校验IP地址
     * @return 返回true标识IP有效， 返回false标识无效
     */
    public static boolean checkIp(String ipAddress) {
        try {
            Matcher matcher = IP_PATTERN.matcher(ipAddress);
            boolean ok = matcher.matches();
            return ok;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 判断是否为精确的、有效IPV6
     *
     * @param ipAddress 待校验IP地址
     * @return 返回true标识IP有效， 返回false标识无效
     */
    public static boolean checkIpV6(String ipAddress) {
        try {
            Matcher matcher = IPV6_PATTERN.matcher(ipAddress);
            boolean ok = matcher.matches();
            return ok;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 提取IPV6
     *
     * @param ipAddressStr
     * @return
     */
    public static String parseIpV6(String ipAddressStr) {
        try {
            Matcher matcher = IPV6_PATTERN.matcher(ipAddressStr);
            boolean ok = matcher.find();
            if (ok) {
                String value = matcher.group();
                return value;
            }
        } catch (Exception e) {
            return StringUtils.EMPTY;
        }
        return StringUtils.EMPTY;
    }


    /**
     * 校验单个精确IP地址是否位于内网段
     *
     * @param ipAddress
     * @return
     */
    private static IpZoneTypeEnum convertIpZoneType(String ipAddress) {
        String[] values = ipAddress.split(IP_SPILT_SYMBOL);
        if (values.length != 4) {
            return IpZoneTypeEnum.UNKNOWN;
        }

        Integer v1 = MixAllUtils.parseInteger(values[0]);
        Integer v2 = MixAllUtils.parseInteger(values[1]);

        boolean ok2 = isNumber(values[1]);
        boolean ok3 = isNumber(values[2]);
        boolean ok4 = isNumber(values[3]);

        // 匹配 10.*.*.* 网段
        if (v1 == 10 && ok2 && ok3 && ok4) {
            return IpZoneTypeEnum.INTERNAL_IP; //当前IP是内网IP
        }

        // 匹配 192.168.*.* 网段
        if (v1 == 192 && v2 == 168 && ok3 && ok4) {
            return IpZoneTypeEnum.INTERNAL_IP; //当前IP是内网IP
        }

        // 匹配 172.16.*.*-172.31.*.* 网段
        if (v1 == 172 && (16 <= v2 && v2 <= 31) && ok3 && ok4) {
            return IpZoneTypeEnum.INTERNAL_IP; //当前IP是内网IP
        }

        // 匹配 127.*.*.* 网段
        if (v1 == 127) {
            return IpZoneTypeEnum.INTERNAL_IP; //当前IP是内网IP
        }

        return IpZoneTypeEnum.PUBLIC_IP;
    }

    private static boolean isNumber(String value) {
        try {
            Long.parseLong(value);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    public static void main(String[] args) {
//        System.out.println(checkIp(""));
//        System.out.println(checkIp("null"));
//        System.out.println(checkIp("192.168.1.1"));
//        System.out.println(checkIp("256.2.3.4"));
//        System.out.println(checkIp("1.2.3.4"));
//        System.out.println(checkIp("1.2.3.4.5"));
//        System.out.println(checkIp("1.2.3.4."));
//        System.out.println(checkPublicIp("192.168.146.125"));
        System.out.println(checkIpV6("240e:341:7d03:3300:fde6:eeed:2c8a:d003"));
        System.out.println(checkIpV6("240e:458:2:a96c:ec5f:a643:5ada:2454"));
        System.out.println(checkIpV6("Mozilla/5.0 (Linux; Android 9"));
    }


}